package com.rsbot;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @program: java-async-network
 * @author: Mr.Han
 * @create: 2025-09-05 16:56
 **/
public class AgentProxy {
    //agent server
    //gateway server
    private static final String REAL_LOGIN_SERVER_HOST = "120.92.23.83"; // 例如 login.csro.com
    private static final int REAL_LOGIN_SERVER_PORT = 32232; // cSRO-R 默认登录端口

    // 代理监听端口（客户端连接到 localhost:LOCAL_PORT）
    private static final int LOCAL_PORT = 32232; // 建议与登录服务器端口相同，客户端无需改配置

    // 连接映射
    private static final Map<SocketChannel, SocketChannel> clientToServerMap = new HashMap<>();
    private static final Map<SocketChannel, SocketChannel> serverToClientMap = new HashMap<>();

    public static void main(String[] args) throws IOException, InterruptedException {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress("127.0.0.1", LOCAL_PORT));
        serverSocket.configureBlocking(false);
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("Proxy listening on localhost:" + LOCAL_PORT);

        while (true) {
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iter = selectedKeys.iterator();

            while (iter.hasNext()) {
                SelectionKey key = iter.next();

                if (key.isAcceptable()) {
                    handleAccept(key, selector);
                } else if (key.isReadable()) {
                    handleRead(key);
                }

                iter.remove();
            }
        }
    }

    private static void handleAccept(SelectionKey key, Selector selector) throws IOException, InterruptedException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        SocketChannel client = server.accept();
        client.configureBlocking(false);

        // 连接到登录服务器
        SocketChannel serverChannel = SocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.connect(new InetSocketAddress(REAL_LOGIN_SERVER_HOST, REAL_LOGIN_SERVER_PORT));
        while (!serverChannel.finishConnect()) {
            // 等待
            Thread.sleep(100);
        }
        System.out.println("已连接agent服务器");
        client.register(selector, SelectionKey.OP_READ);
        serverChannel.register(selector, SelectionKey.OP_READ);
        clientToServerMap.put(client, serverChannel);
        serverToClientMap.put(serverChannel, client);
    }

    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel from = (SocketChannel) key.channel();
        SocketChannel to = clientToServerMap.get(from);
        if (to == null) {
            to = serverToClientMap.get(from);
        }
        if (to == null) {
            return;
        }

        ByteBuffer buffer = ByteBuffer.allocate(4096);
        int bytesRead = from.read(buffer);
        if (bytesRead == -1) {
            from.close();
            to.close();
            clientToServerMap.remove(from);
            serverToClientMap.remove(to);
            return;
        }

        buffer.flip();

        // 从服务端读取，检查封包
        if (serverToClientMap.containsKey(from)) {
            processServerPackets(buffer, from);
        }

        // 转发
        to.write(buffer);
    }

    private static void processServerPackets(ByteBuffer buffer, SocketChannel serverChannel) throws IOException {
        // 打印完整的接收到的数据
        System.out.println("收到服务器数据，长度: " + buffer.remaining() + " 字节");

        // 复制缓冲区数据用于打印（不影响原始缓冲区）
        ByteBuffer copyBuffer = buffer.duplicate();
        byte[] rawData = new byte[copyBuffer.remaining()];
        copyBuffer.get(rawData);

        System.out.println("原始十六进制数据:");
        for (int i = 0; i < rawData.length; i++) {
            System.out.printf("%02X ", rawData[i]);
            if ((i + 1) % 16 == 0) {
                System.out.println();
            }
        }
        System.out.println("\n");
    }
}
